﻿using System;
using System.Globalization;
using Istace.Framework.Mapping.Core.Interfaces;

namespace Istace.Framework.Mapping.Core
{
    /// <summary>
    /// Represent type implemented by a mapper
    /// </summary>
    public class MappingTuple : IComparable, IMappingTuple
    {
        #region Public properties
        /// <summary>
        /// The source mapper type
        /// </summary>
        public Type Source { get ; private set; }

        /// <summary>
        /// The destination mapper type
        /// </summary>
        public Type Destination { get; private set; }
        #endregion

        #region Public .ctor
        /// <summary>
        /// Default .ctor
        /// </summary>
        /// <param name="source">The source mapper type</param>
        /// <param name="destination">The destination mapper type</param>
        public MappingTuple(Type source, Type destination)
        {
            this.Source = source;
            this.Destination = destination;
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Convert a MappingTuple to his string representation
        /// </summary>
        /// <returns></returns>
        public override sealed string ToString()
        {
            return String.Format(CultureInfo.InvariantCulture, "MapperOf{0}To{1}", this.Source.FullName, this.Destination.FullName);
        }

        /// <summary>
        /// Determines whether the specified <see cref="System.Object" /> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
        /// <returns>
        ///   <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        public override bool Equals(object obj)
        {
            return this.CompareTo(obj) == 0;
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            return this.Source.GetHashCode() + this.Destination.GetHashCode();
        }

        /// <summary>
        /// Compare two IMappingTuple
        /// </summary>
        /// <param name="instance">The object to compare</param>
        /// <returns>
        /// Return 0 if the same, -1 else
        /// </returns>
        /// <exception cref="System.ArgumentException">Bad type comparaison.</exception>
        public int CompareTo(object instance)
        {
            if (instance == null) 
                return -1;

            MappingTuple tuple = instance as MappingTuple;
            
            if (((object)tuple) == null) 
                throw new ArgumentException("Bad type comparaison.");

            return tuple.ToString().Equals(this.ToString()) ? 0 : -1;
        }
        #endregion

        #region Operator overload
        /// <summary>
        /// Override equality sign
        /// </summary>
        /// <param name="mappingTuple1">The mapping tuple1.</param>
        /// <param name="mappingTuple2">The mapping tuple2.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        public static bool operator ==(MappingTuple mappingTuple1, MappingTuple mappingTuple2)
        {
            if ( ReferenceEquals(mappingTuple1, null) && ReferenceEquals(mappingTuple2, null)) return true;
            if ( ReferenceEquals(mappingTuple1, null) ) return false;

            return mappingTuple1.CompareTo(mappingTuple2) == 0;
        }

        /// <summary>
        /// Override diff sign
        /// </summary>
        /// <param name="mappingTuple1">The mapping tuple1.</param>
        /// <param name="mappingTuple2">The mapping tuple2.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        public static bool operator !=(MappingTuple mappingTuple1, MappingTuple mappingTuple2)
        {
            return !(mappingTuple1 == mappingTuple2);
        }

        /// <summary>
        /// Override greater than sign
        /// </summary>
        /// <param name="mappingTuple1">The mapping tuple1.</param>
        /// <param name="mappingTuple2">The mapping tuple2.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        public static bool operator >(MappingTuple mappingTuple1, MappingTuple mappingTuple2)
        {
            if (ReferenceEquals(mappingTuple1, null)) throw new ArgumentNullException("mappingTuple1");
            if (ReferenceEquals(mappingTuple2, null)) throw new ArgumentNullException("mappingTuple2"); 
            return String.Compare(mappingTuple1.ToString(), mappingTuple2.ToString(), StringComparison.Ordinal) > 0;
        }

        /// <summary>
        /// Override lesser than sign
        /// </summary>
        /// <param name="mappingTuple1">The mapping tuple1.</param>
        /// <param name="mappingTuple2">The mapping tuple2.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException"></exception>
        public static bool operator <(MappingTuple mappingTuple1, MappingTuple mappingTuple2)
        {
            if (ReferenceEquals(mappingTuple1, null)) throw new ArgumentNullException("mappingTuple1");
            if (ReferenceEquals(mappingTuple2, null)) throw new ArgumentNullException("mappingTuple2");
            return String.Compare(mappingTuple1.ToString(), mappingTuple2.ToString(), StringComparison.Ordinal) < 0;
        }
        #endregion
    }
}
